#include "math/geometry.h"

namespace math{

ToPlaneRelation Triangle::QualifyPoint(const Vector3 & point) const {
    Vector3 diff(point - GetP0()->point_);
    float dot = cml::dot(GetNormal(), diff);
    
    //use generic tolerance to allow for near zero value
    if(abs(dot) < math::kTolerance )
        return math::ON_PLANE;

    if(dot > 0)
        return math::POSITIVE_SIDE;
    else if(dot < 0)
        return math::NEGATIVE_SIDE;
    else 
        return math::ON_PLANE; //this code should never be reached. just here for sanity's sake
}
ToPlaneRelation Triangle::QualifyTriangle(const Triangle & triangle) const {
    ToPlaneRelation p0 = QualifyPoint(triangle.GetP0()->point_);
    ToPlaneRelation p1 = QualifyPoint(triangle.GetP1()->point_);
    ToPlaneRelation p2 = QualifyPoint(triangle.GetP2()->point_);
    
    //the most common case is that the triangle is entirely on one side of the plane or the other
    //so do a quick test to eliminate the common case first
    if( p0 == p1 && p0 == p2)
        return p0;
    
    int combined_values = (int)p0 | (int)p1 | (int)p2;
    bool has_positive = (combined_values & (int)math::POSITIVE_SIDE) != 0;
    bool has_negative = (combined_values & (int)math::NEGATIVE_SIDE) != 0;

    if( has_positive && has_negative )
        return math::SPANNING;
    else if( has_positive )
        return math::POSITIVE_SIDE;
    else return math::NEGATIVE_SIDE;
}
 
 
ToPlaneRelation Plane::QualifyPoint(const Vector3 & point) const {
    Vector3 diff = point - GetPoint()->point_;
    float dot = cml::dot(GetNormal(), diff);
    
    //use generic tolerance to allow for near zero value
    if(abs(dot) < math::kTolerance )
        return math::ON_PLANE;

    if(dot > 0)
        return math::POSITIVE_SIDE;
    else if(dot < 0)
        return math::NEGATIVE_SIDE;
    else
        return math::ON_PLANE;  //this code should never be reached. just here for sanity's sake
}
ToPlaneRelation Plane::QualifyTriangle(const Triangle & triangle) const {
    ToPlaneRelation p0 = QualifyPoint(triangle.GetP0()->point_);
    ToPlaneRelation p1 = QualifyPoint(triangle.GetP1()->point_);
    ToPlaneRelation p2 = QualifyPoint(triangle.GetP2()->point_);
    
    //the most common case is that the triangle is entirely on one side of the plane or the other
    //so do a quick test to eliminate the common case first
    if( p0 == p1 && p0 == p2)   
        return p0;
    
    int combined_values = (int)p0 | (int)p1 | (int)p2;

    bool has_positive = (combined_values & (int)math::POSITIVE_SIDE) != 0;
    bool has_negative = (combined_values & (int)math::NEGATIVE_SIDE) != 0;

    if( has_positive && has_negative )
        return math::SPANNING;
    else if( has_positive )
        return math::POSITIVE_SIDE;
    else return math::NEGATIVE_SIDE;

}




} //namespace